// @Describe: 服务器控制模块
package core

import (
	"context"
	"github.com/rs/zerolog/log"
	"github.com/spf13/viper"
	"google.golang.org/grpc"
	"net"
	"os"
	"os/signal"
	"syscall"
	"wormhole/pkg/event"
	"wormhole/pkg/udp"
	"wormhole/protos/hole"
)

var SingleChan chan int

func init() {
	SingleChan = make(chan int, 1)
}
func SendSingle2Server(e int) {
	SingleChan <- e
}

// Controller
//  @Description: 通过信号进行控制，可解耦外部命令为异步非阻塞控制
func Controller() {
	// 处理系统停止信号
	sysSingle := make(chan os.Signal, 1)
	signal.Notify(sysSingle, syscall.SIGINT, syscall.SIGTERM)
	// 处理应用事件
	svc := GetHoleServer()
	for {
		select {
		case e := <-SingleChan:
			switch e {
			case event.Start:
				log.Info().Msg("start")
				go svc.start()
			case event.Stop:
				log.Info().Msg("stop")
				svc.stop()
				return
			case event.Restart:
				log.Info().Msg("restart")
				server.stop()
				go svc.start()
			}
		case <-sysSingle:
			log.Info().Msg("stop")
			svc.stop()
			return
		}
	}
}

// start
//  @Description: 启动服务
//  @receiver s
func (s *holeServer) start() {
	// 初始化配置
	if viper.GetString("core.ip") == "" {
		log.Fatal().Msg("本机ip获取失败,无法启动服务,需手动添加到配置文件!")
	}
	port := viper.GetString("core.port")
	// 启动client测试通信
	conn, _ := grpc.Dial("localhost:"+port, grpc.WithInsecure())
	c := hole.NewHoleClient(conn)
	_, err := c.CheckHealth(context.Background(), new(hole.Empty))
	if err == nil {
		log.Fatal().Msg("运行失败:已有服务正在运行")
	}
	_ = conn.Close()
	// 启动设备发现
	s.Ctx, s.Cancel = context.WithCancel(context.Background())
	go s.ListenUdp()
	go udp.Broadcast()
	nets := viper.GetStringSlice("nets")
	for _, targetNet := range nets {
		go func(targetNet string) {
			udp.AddNet(targetNet)
		}(targetNet)
	}
	s.Listen()
}

// stop
//  @Description: 关闭服务
//  @receiver s
func (s *holeServer) stop() {
	// 清理任务
	if s.Cancel != nil {
		s.Cancel()
	}
	// 发送下线广播
	for ip := range s.IpMap {
		ripple := &hole.Ripple{
			Ip:    ip,
			Port:  viper.GetInt32("core.port"),
			Event: event.OfflineEvent,
		}
		log.Debug().Str("ip", ip).Msg("stop and send event to ip")
		_ = udp.Dimple(ripple)
	}
	// 持久化在线设备信息
	netMap := make(map[string]bool)
	historyNets := viper.GetStringSlice("nets")
	for _, ip := range historyNets {
		netMap[ip] = true
	}
	for ip := range s.IpMap {
		if ip == viper.GetString("core.ip") {
			continue
		}
		netMap[ip] = true
	}
	nets := make([]string, 0)
	for ip := range netMap {
		nets = append(nets, ip)
	}
	viper.Set("nets", nets)
	err := viper.WriteConfig()
	if err != nil {
		log.Err(err).Msg("写入配置文件失败")
	}
	s.clear()
}

func (s *holeServer) Stop(ctx context.Context, empty *hole.Empty) (*hole.Reply, error) {
	defer SendSingle2Server(event.Stop)
	return new(hole.Reply), nil
}

func (s *holeServer) Restart(ctx context.Context, empty *hole.Empty) (*hole.Reply, error) {
	go SendSingle2Server(event.Restart)
	return new(hole.Reply), nil
}

// Listen
//  @Description: 监听服务
//  @receiver s
func (s *holeServer) Listen() {
	localName := viper.GetString("core.name")
	heat := &hole.Ripple{
		Ip:   viper.GetString("core.ip"),
		Name: localName,
		Port: viper.GetInt32("core.port"),
	}
	s.OnlineDevice(heat)
	lis, err := net.Listen("tcp", "0.0.0.0:"+viper.GetString("core.port"))
	if err != nil {
		log.Err(err).Send()
		return
	}
	srv := grpc.NewServer()
	go func() {
		_ = <-s.Ctx.Done()
		srv.Stop()
	}()
	hole.RegisterHoleServer(srv, s)
	err = srv.Serve(lis)
	if err != nil {
		log.Fatal().Err(err).Msg("服务启动失败")
	}
}
